"""

    Lamptop development utilities
    Copyright (C) 2011  Colby T. Sollars

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
"""

import os
import os.path
from ApacheConfig import ApacheConfig
import urllib
import time
import stat
import re

class virtualhost:
    filepath = ""
    servername = ""
    document_root = ""
    serveraliases = None #Array
    
    def __init__(self):
        self.serveraliases = []

class apacheconf:
    configs = None #array
    virtualhosts = None #array
    config_dir = '/etc/apache2/'
    
    def __init__(self):
        self.configs = {}
        self.virtualhosts = []
        self._load_configs()
        self._load_virtualhosts()
    
    def _load_configs(self):
        self.configs['/etc/apache2/apache2.conf'] = \
            ApacheConfig.parse_file('/etc/apache2/apache2.conf')
        self.configs['/etc/apache2/httpd.conf'] = \
            ApacheConfig.parse_file('/etc/apache2/httpd.conf')
        for fname in os.listdir(self.config_dir + 'sites-available'):
            if fname[0] == '.':
                continue
            self.configs[self.config_dir + 'sites-available/' + fname] = \
                ApacheConfig.parse_file(self.config_dir + 'sites-available/' + \
                fname)
    
    def _load_virtualhosts(self):
        for config_file in self.configs:
            vhosts = []
            self._get_child_virtualhosts(config_file, self.configs[config_file], vhosts)
            self.virtualhosts.extend(vhosts)
    
    def _get_child_virtualhosts(self, config_file, config_obj, vhosts):
        for child in config_obj.children:
            if child.name == "VirtualHost":
                new_vhost = virtualhost()
                new_vhost.filepath = config_file
                ac_config_vhost = child.find("ServerName")
                if ac_config_vhost:
                    new_vhost.servername = ac_config_vhost.values[0]
                    ac_config_alias = child.find("ServerAlias")
                    if ac_config_alias:
                        new_vhost.serveraliases.extend(ac_config_alias.values)
                    vhosts.append(new_vhost)
                    self._get_child_virtualhosts(config_file, child, vhosts)
    
    def find_virtualhost(self, vhost_name):
        """
            Searches virtualhosts for ServerName or ServerAlias
            
            Returns:
                virtualhost Object if match is found, None if not.
        """
        
        for vhost in self.virtualhosts:
            if vhost.servername == vhost_name:
                return vhost
            if vhost_name in vhost.serveraliases:
                return vhost
        return None

class lamptopVirtualhost:
    def __init__(self):
        self.ac = apacheconf()
    
    def validate_new_hostname(self, hostname):
        errors = []
        if not self.check_disallowed_chars(hostname):
            errors.append("Virtualhost name contains disallowed characters")
        vhost_obj = self.ac.find_virtualhost(hostname)
        if vhost_obj:
            errors.append("Virtualhost name '%s' already taken. Configured in file %s" % \
            (hostname, vhost_obj.filepath))
        return errors
    
    def validate_new_root_path(self, root_path):
        error_list = []
        if os.path.exists(root_path):
            error_list.append("Specified path already exists")
        if not os.path.exists(os.path.dirname(root_path)):
            error_list.append("Parent directory of specified path does not exist")
        else:
            if not os.access(os.path.dirname(root_path), os.W_OK):
                error_list.append("Parent directory not writable")
        return error_list
    
    def check_disallowed_chars(self, string):
        if not string == urllib.pathname2url(string):
            return False
        return True
    
    def create_virtualhost(self, hostname, document_root, host_file_path,\
    localhost_ip, docroot_uid=0, docroot_gid=0):
        errors = []
        errors.extend(self.validate_new_hostname(hostname))
        errors.extend(self.validate_new_root_path(document_root))
        if len(errors):
            return errors
        
        """
            make config file
        """
        template = open("./vhost_template", "r")
        config_content = template.read()
        template.close()
        config_content = config_content.replace("{servername}", hostname)
        config_content = config_content.replace("{document_root}", document_root)
        host_file = open(self.ac.config_dir + "sites-available/" + \
        hostname, "w")
        host_file.write(config_content)
        host_file.close()
        os.symlink(self.ac.config_dir + "sites-available/" + \
        hostname, self.ac.config_dir + "sites-enabled/" + \
        hostname)
        
        """
            Update hosts file
        """
        hosts_file = open(host_file_path, "r+")
        hosts_content = hosts_file.read()
        hosts_file.seek(0)
        hosts_file.truncate()
        backup_file = open(os.path.dirname(host_file_path) + "/hosts.backup." + str(time.time()), "w")
        backup_file.write(hosts_content)
        backup_file.close()
        
        #find the IP we're trying to add a hostname to
        result = re.search(localhost_ip.replace(".", "\.") + "([ \t\f\v]*.*)", hosts_content)
        if result:
            if result.group(1):
                hosts_content = hosts_content.replace(result.group(1), \
                result.group(1) + " " + hostname)
            else:
                hosts_content = hosts_content.replace(result.group(0), \
                result.group(0) + "\t" + hostname)
        else:
            hosts_content+= "\n" + localhost_ip + "\t" + hostname
        hosts_file.write(hosts_content)
        hosts_file.close()
        
        """
            Set up document root
        """
        os.mkdir(document_root)
        os.chmod(document_root, \
            stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|\
            stat.S_IRGRP|stat.S_IWGRP|stat.S_IXGRP|\
            stat.S_IROTH|stat.S_IXOTH)
        os.chown(document_root, docroot_uid, docroot_gid)
        return errors
